using System;
using System.Collections.Generic;
using KBEngine;
using UnityEngine.Assertions;

//////////////////////////////////////////////////////////////////////////////////////////////
public class ServerContainerProperty
{
	/// Account的成员变量
	/// 包含了修改本地数据的消息，无需把消息发送出去的消息号
	static public List<Int32> dataChangedMsg = new List<Int32> {
		MsgDef.SVR2CLIENT_CONTAINER_SYNC_MSG,
	};

	private WeakReference owner;

	public ServerContainerProperty(Entity owner)
	{
		this.owner = new WeakReference(owner);
	}

	// 这里如果有更好的实现方式请告知一下，邮箱 952670771@qq.com
	// 这三种类型包含服务器两层字典的缓存数据
	private Dictionary<string, Dictionary<object, object>> L1 = new Dictionary<string, Dictionary<object, object>>();
	private Dictionary<string, Dictionary<object, Dictionary<object, object>>> L2 = new Dictionary<string, Dictionary<object, Dictionary<object, object>>>();
	private Dictionary<string, Dictionary<object, Dictionary<object, Dictionary<object, object>>>> L3 = new Dictionary<string, Dictionary<object, Dictionary<object, Dictionary<object, object>>>> ();

	public object GetContainerProp(string propName)
	{
		if ( ! owner.IsAlive)
		{
			return null;
		}

		Dictionary<object, object>  propL1;
		if (L1.TryGetValue(propName, out propL1))
		{
			return propL1;
		}

		Dictionary<object, Dictionary<object, object>> propL2;
		if (L2.TryGetValue(propName, out propL2))
		{
			return propL2;
		}

		Dictionary<object, Dictionary<object, Dictionary<object, object>>> propL3;
		if (L3.TryGetValue(propName, out propL3))
		{
			return propL3;
		}

		return null;
	}

	public void handleChangeDataMsg(List<object> listMsg)
	{
		if (!owner.IsAlive)
		{
			return;
		}

		Int32 msgID = Convert.ToInt32(listMsg[0]);
		switch(msgID)
		{
			case MsgDef.SVR2CLIENT_CONTAINER_SYNC_MSG:
				handleContainerSync(listMsg);
				break;
		}
	}

	private void handleContainerSync(List<object> listMsg)
	{
		string propName = Convert.ToString(listMsg[1]);
		Int32 changeType = Convert.ToInt32(listMsg[2]);
		string notifyData = Convert.ToString(listMsg[3]);

		Dictionary<object, object> oldValsL1 = new Dictionary<object, object>();
		Dictionary<object, Dictionary<object, object>> oldValsL2 = new Dictionary<object, Dictionary<object, object>>();
		Dictionary<object, Dictionary<object, Dictionary<object, object>>> oldValsL3 = new Dictionary<object, Dictionary<object, Dictionary<object, object>>>();
		int layer = 0;
		string[] keysValsStrList = notifyData.Split(new char[2] { '{','}'},StringSplitOptions.RemoveEmptyEntries);
		for(int i = 0; i < keysValsStrList.Length; ++i)
		{
			// 从顶层的key到最底层的value的字符串值和数字类型
			string[] strValsAndNumTypes = keysValsStrList[i].Split(new char[2] { '(',')'}, StringSplitOptions.RemoveEmptyEntries);
			// 至少有一层key和value
			Assert.IsTrue(strValsAndNumTypes.Length >= 2);

			// 第一层的key值的字符串 和key的数字类型
			string[] strKeyL1AndNumType = strValsAndNumTypes[0].Split(new char[2] { '=','>'}, StringSplitOptions.RemoveEmptyEntries);
			string strkeyL1 = strKeyL1AndNumType[0];
			SByte keyL1NumType = Convert.ToSByte(strKeyL1AndNumType[1]);
			// 第一层dict key的值
			object keyL1 = Kernel.Instance().getStrRealVal(strkeyL1, keyL1NumType);

			// 当前层value值的字符串和value的数字类型
			string[] strValAndNumType = strValsAndNumTypes[strValsAndNumTypes.Length - 1].Split(new char[2] { '=', '>' }, StringSplitOptions.RemoveEmptyEntries);
			string strVal = strValAndNumType[0];
			SByte valNumType = Convert.ToSByte(strValAndNumType[1]);
			// 最里层的dict的value的值
			object val = Kernel.Instance().getStrRealVal(strVal, valNumType);

			//减去val占用的位置数
			layer = strValsAndNumTypes.Length - 1;
			if (layer == 1)
			{
				handleL1ContainerChange(propName, keyL1, val, changeType, oldValsL1);
				continue;
			}

			// 第2层的key值的字符串 和key的数字类型
			string[] strKeyL2AndNumType = strValsAndNumTypes[1].Split(new char[2] { '=', '>' }, StringSplitOptions.RemoveEmptyEntries);
			string strkeyL2 = strKeyL2AndNumType[0];
			SByte keyL2NumType = Convert.ToSByte(strKeyL2AndNumType[1]);
			// 第2层dict key的值
			object keyL2 = Kernel.Instance().getStrRealVal(strkeyL2, keyL2NumType);

			if(layer == 2)
			{
				handleL2ContainerChange(propName, keyL1, keyL2, val, changeType, oldValsL2);
				continue;
			}

			if(layer == 3)
			{
				handleL3ContainerChange();
			}
		}

		Int32 id = (owner.Target as Entity).id;

		if (layer == 1)
		{
			KBEngine.Event.fireOut("onContainerPropChanged", id, propName, oldValsL1, changeType);
		}

		if (layer == 2)
		{
			KBEngine.Event.fireOut("onContainerPropChanged", id, propName, oldValsL2, changeType);
		}

		if (layer == 3)
		{
			KBEngine.Event.fireOut("onContainerPropChanged", id, propName, oldValsL3, changeType);
		}
	}

	private void handleL1ContainerChange(string propName, object keyL1, object val, Int32 changeType, Dictionary<object, object> oldValsL1)
	{
		Dictionary<object, object> propContainerL1;
		if (!L1.TryGetValue(propName, out propContainerL1))
		{
			L1.Add(propName, new Dictionary<object, object>());
			L1.TryGetValue(propName, out propContainerL1);
		}

		if (keyL1 == null)
		{
			return;
		}

		if (changeType == ValChangedDef.DATA_REMOVE)
		{
			oldValsL1[keyL1] = propContainerL1[keyL1];
			propContainerL1.Remove(keyL1);
		}
		else
		{
			object oldVal;
			propContainerL1.TryGetValue(keyL1, out oldVal);
			oldValsL1[keyL1] = oldVal;

			propContainerL1[keyL1] = val;
		}
	}

	private void handleL2ContainerChange(string propName, object keyL1, object keyL2, object val, Int32 changeType, Dictionary<object, Dictionary<object, object>> oldValsL2)
	{
		Dictionary<object, Dictionary<object, object>> propContainerL2;
		if (!L2.TryGetValue(propName, out propContainerL2))
		{
			L2.Add(propName, new Dictionary<object, Dictionary<object, object>>());
			L2.TryGetValue(propName, out propContainerL2);
		}

		if (keyL1 == null)
		{
			return;
		}

		if (changeType == ValChangedDef.DATA_REMOVE)
		{
			oldValsL2[keyL1] = propContainerL2[keyL1];
			propContainerL2.Remove(keyL1);
		}
		else
		{
			Dictionary<object, object> propContainerL2K2;
			if (!propContainerL2.TryGetValue(keyL1, out propContainerL2K2))
			{
				propContainerL2.Add(keyL1, new Dictionary<object, object>());
				propContainerL2.TryGetValue(keyL1, out propContainerL2K2);
			}

			object oldVal;
			propContainerL2K2.TryGetValue(keyL2, out oldVal);

			Dictionary<object, object> oldPropContainerL2K2;
			if(! oldValsL2.TryGetValue(keyL1, out oldPropContainerL2K2))
			{
				oldValsL2[keyL1] = new Dictionary<object, object>();
			}

			oldValsL2[keyL1][keyL2] = oldVal;
			propContainerL2K2[keyL2] = val;
		}
	}

	private void handleL3ContainerChange()
	{

	}
}
